package cn.ftp;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

public class FTPServer {
	
	private String home = "D:/FTP/server/";
	private ServerSocket serverSocket = null;
	
	public FTPServer(String homeDir) {
		if (homeDir != null) {
			if (!MyUtil.checkDirValid(homeDir)) {
				System.out.println("Invalid home directory!");
			} else {
				home = homeDir;
			}
		}
		if (!home.endsWith("/")) {
			home = home + "/";
		}
		
		try {
			serverSocket = new ServerSocket(MyUtil.defaultPort);
		} catch (IOException e) {
			System.out.println("Cannot listen to: " + e);
		}
		
		while (true) {
			Socket socket = null;
			try {
				socket = serverSocket.accept();
			} catch (IOException e) {
				System.out.println("Error! " + e);
			}
			if (socket != null) {
				ServerHandler serverHandler = new ServerHandler(socket, home);
				Thread handlerThread = new Thread(serverHandler);
				handlerThread.start();
				System.out.println("A client is connected");
			}
		}
	}
}


class ServerHandler extends FTPHandler implements Runnable{
	private Socket socket = null;
	
	private String homeDir = "D:/FTP/server/";
	private String dirFile = "dirInfo";
	private String currentDir = "";
	
	public ServerHandler(Socket socket, String path) {
		super(socket);
		this.socket = socket;
		homeDir = path;
	}
	
	public void run() {
//		System.out.print("ServerHandler is running on port ");
//		System.out.println(socket.getPort());
		
		super.writeLine("220 WY's FTP");
		
		while (super.isReady()) {
			String line = super.readLine();
			if (line == null) {
				break;
			}
			boolean isExit = false;
//			System.out.println(line);
			
			line = line.trim();
			String strCommand = null;
			if (line.contains(MyUtil.SP)) {
				strCommand = line.substring(0, line.indexOf(MyUtil.SP));
			} else {
				strCommand = line;
			}
			String content = MyUtil.getContent(line);
			String filepath = null;
			int newport = 0;
			
			MyUtil.Command command = MyUtil.Command.valueOf(strCommand);
			String pathname = null;
			StringBuilder builder = new StringBuilder();
			switch (command) {
			case USER:	// 331
				builder.append(331);
				builder.append(MyUtil.SP);
				builder.append("Please specify the password");
				break;
			case PASS:	// 230
				builder.append(230);
				builder.append(MyUtil.SP);
				builder.append("Login successful");
				break;
			case SYST:	// 215
				builder.append(215);
				builder.append(MyUtil.SP);
				builder.append("WY System");
				break;
			case PWD: 	// 257
				builder.append(257);
				builder.append(MyUtil.SP);
				builder.append(this.homeDir + this.currentDir);
				break;
			case TYPE:	// 
				builder.append(200);
				builder.append(MyUtil.SP);
				builder.append("Command ok");
				break;
			case PASV:	// 227
			case EPSV:
				builder.append(227);
				builder.append(MyUtil.SP);
				Random r = new Random();
				newport = r.nextInt(15536) + 1024;
				super.buildTransServer(newport);
				System.out.println("PASV MODE: port = " + newport);
				builder.append("PASV done. New port (|||" + newport + "|)");
				break;
			case RETR:	// 150
				builder.append(150);
				builder.append(MyUtil.SP);
				filepath = MyUtil.getContent(line);
				filepath = this.homeDir + this.currentDir + filepath;
				builder.append(filepath);
				super.setPath(filepath, true);
				break;
			case STOR:	// 150
				builder.append(150);
				builder.append(MyUtil.SP);
				filepath = MyUtil.getContent(line);
				filepath = filepath.substring(filepath.lastIndexOf("/") + 1);
				filepath = this.homeDir + this.currentDir;
				
				builder.append(filepath);
				super.setPath(filepath, false);
				break;
				
			case LIST: // 150
				this.genDirFile();
				builder.append(150);
				builder.append(MyUtil.SP);
				filepath = this.homeDir + this.dirFile;
				builder.append(filepath);
				super.setPath(filepath, true);
				break;
			case CWD: // 200
				builder.append(200);
				if (content.equals("..")) {
					if (currentDir.contains("/")) {
						currentDir = currentDir.substring(0, currentDir.lastIndexOf("/"));
					} else {
						currentDir = "";
					}
				} else {
					currentDir += content + "/";
				}
				break;
			case HELP:	// 150
				this.genInfoFile();
				builder.append(150);
				builder.append(MyUtil.SP);
				filepath = this.homeDir + dirFile;
				builder.append(filepath);
				super.setPath(filepath, true);
				break;
			case QUIT:	// 221
				builder.append(221);
				builder.append(MyUtil.SP);
				builder.append("Goodbye!");
				isExit = true;
				super.close();
				break;
			default:
				System.out.println("Unrecognized command: " + command.toString());
				builder.append(200);
				builder.append(MyUtil.SP);
				builder.append("Command ok");
				break;
			}
			if (builder.length() > 0 && !isExit) {
				super.writeLine(builder.toString());
			}
			if (isExit) {
				System.out.println("Client disconnect normally");
				break;
			}
			
		}
		System.out.println("The FTPHandler is over");
		super.close();
	}
	
	public void genInfoFile() {
		MyFileWriter mfw = new MyFileWriter(homeDir + dirFile, true);
		mfw.write("put <file name>   : upload a file to remote ftp server\n");
		mfw.write("get <file name>   : download a file to remote ftp server\n");
		mfw.write("pwd               : get the current directory\n");
		mfw.write("dir               : get the list of files and folders\n");
		mfw.write("cd <folder name>	 : go to folder\n");
		mfw.write("?                 : see this help info\n");
		mfw.write("quit              : disconnect from remote ftp server\n");
		mfw.close();
	}
	
	public void genDirFile() {
		File f = new File(this.homeDir + this.currentDir);
		String[] list = f.list();
		MyFileWriter mfw = new MyFileWriter(homeDir + dirFile, true);
		for (int i = 0; i < list.length; i++) {
			if (!list[i].equals(dirFile)) {
				mfw.write(list[i] + "\n");
			}
		}
		mfw.close();
	}
	
}